<script setup lang="ts">
import { watch, ref, onMounted } from 'vue'
import HumbleiconsChevronDown from '~icons/humbleicons/chevron-down'
import HumbleiconsVolume2 from '~icons/humbleicons/volume-2'
// import HumbleiconsPlus from '~icons/humbleicons/plus'
import HumbleiconsPlay from '~icons/humbleicons/play'
import HumbleiconsPause from '~icons/humbleicons/pause'
import HumbleiconsSkipBackward from '~icons/humbleicons/skip-backward'
import HumbleiconsSkipForward from '~icons/humbleicons/skip-forward'
import { usePlayerStore } from '@renderer/stores/player'
import { storeToRefs } from 'pinia'
import VueSlider from 'vue-slider-component'
import 'vue-slider-component/theme/default.css'
import { formatSeconds } from '@renderer/tools/index'
import ColorThief from 'colorthief/dist/color-thief.mjs'
import Color from 'color'
import { useLyricsStore } from '@renderer/stores/lyrics'
import Favorite from '@renderer/components/Favorite.vue'

const { isAudioPlay, currentTime, duration, playingData } = storeToRefs(usePlayerStore())
const { audioNext, audioPrev, audioPlay, audioPause, setAudioCurrentTime } = usePlayerStore()
const { showLyrics } = storeToRefs(useLyricsStore())
const { toggleLyrics } = useLyricsStore()
const coverImgRef = ref<HTMLImageElement>()
const lyricsBgStyle = ref({})

onMounted(() => {
  // 使用onMounted是为了等待imgElem加载完成
  watch(
    () => playingData.value?.cover,
    async (url) => {
      try {
        if (!url) throw new Error('封面地址为空')
        new URL(url)
        const imgElem = coverImgRef.value
        if (!imgElem) throw new Error('封面元素获取失败')

        // 图片转base64，是因为colorThief会提示跨域
        const base64 = await imageUrlToBase64(url + '@512w_512h_1c')
        if (base64) {
          if (coverImgRef.value) imgElem.src = base64
          imgElem.onload = () => {
            generateLyricsBgStyle(imgElem)
          }
        }
      } catch (e) {
        if (e instanceof Error) {
          console.error(e.message)
        } else {
          console.error(e)
        }
      }
    },
    {
      immediate: true
    }
  )
})

// 网络图片转Base64数据
async function imageUrlToBase64(imageUrl: string): Promise<string | null> {
  try {
    const response = await fetch(imageUrl)
    if (!response.ok) throw new Error('封面图片请求失败')

    const blob = await response.blob()
    return new Promise((resolve, reject) => {
      const reader = new FileReader()
      reader.onloadend = () => resolve(reader.result as string)
      reader.onerror = reject
      reader.readAsDataURL(blob)
    })
  } catch (e) {
    if (e instanceof Error) {
      console.error(e.message)
    } else {
      console.error(e)
    }
  }
  return null
}

// 生成歌词页背景颜色
function generateLyricsBgStyle(image: HTMLImageElement) {
  const colorThief = new ColorThief()
  // 获取主色
  const mainColor = colorThief.getColor(image)
  let rgbData = Color.rgb(...mainColor)
  const lumi = 0.4
  // 避免低亮度的颜色，会导致视觉反光不舒服
  if (rgbData.luminosity() > lumi) {
    // 获取相似颜色
    const varColors = colorThief.getPalette(image)
    for (const varColo of varColors) {
      const varColoData = Color.rgb(...varColo)
      if (varColoData.luminosity() <= lumi) {
        rgbData = varColoData
        break
      }
    }
  }
  const color = rgbData.darken(0.1).string()
  const color2 = rgbData.lighten(0.28).rotate(-30).string()
  lyricsBgStyle.value = {
    background: `linear-gradient(to top left, ${color}, ${color2})`
  }
}
</script>

<template>
  <div :class="['lyrics-page', { visible: showLyrics }]" :style="lyricsBgStyle">
    <div class="left-side">
      <div>
        <div class="cover">
          <img ref="coverImgRef" />
        </div>
        <div class="controls">
          <div class="top-part">
            <div class="track-info">
              <div class="title" :title="playingData?.title">{{ playingData?.title }}</div>
              <div class="subtitle">{{ playingData?.author }}</div>
            </div>
            <div class="top-right">
              <div class="volume-control">
                <button class="button-icon">
                  <HumbleiconsVolume2 class="svg-icon" />
                </button>
              </div>
              <div class="buttons">
                <Favorite v-if="playingData" :data="playingData" />
                <!-- <button>
                  <HumbleiconsPlus class="svg-icon" />
                </button> -->
              </div>
            </div>
          </div>
          <div class="progress-bar">
            <span>{{ formatSeconds(currentTime) }}</span>
            <div class="slider">
              <VueSlider
                :model-value="currentTime"
                :dot-size="12"
                :duration="1"
                :lazy="true"
                tooltip="none"
                :max="duration"
                @change="setAudioCurrentTime"
              />
            </div>
            <span>{{ formatSeconds(duration) }}</span>
          </div>
          <div class="media-controls">
            <button @click="audioPrev">
              <HumbleiconsSkipBackward class="svg-icon" />
            </button>
            <button v-if="isAudioPlay" @click="audioPause">
              <HumbleiconsPause class="svg-icon play" />
            </button>
            <button v-else @click="audioPlay">
              <HumbleiconsPlay class="svg-icon play" />
            </button>
            <button @click="audioNext">
              <HumbleiconsSkipForward class="svg-icon" />
            </button>
          </div>
        </div>
      </div>
    </div>
    <div class="right-side"></div>
    <div class="close-button">
      <button @click="toggleLyrics">
        <HumbleiconsChevronDown class="svg-icon" />
      </button>
    </div>
  </div>
</template>

<style lang="less" scoped>
.lyrics-page {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  z-index: 200;
  background: var(--color-body-bg);
  display: flex;
  clip: rect(auto, auto, auto, auto);
  transform: translateY(100%);
  transition: all 0.4s;

  &.visible {
    transform: translateY(0);
  }

  .left-side {
    flex: 1;
    display: flex;
    justify-content: flex-end;
    margin-right: 32px;
    margin-top: 24px;
    align-items: center;
    transition: all 0.5s;
    z-index: 1;

    .cover {
      position: relative;
      width: 54vh;
      height: 54vh;
      img {
        width: 100%;
        height: 100%;
        border-radius: 0.75em;
        user-select: none;
        pointer-events: none;
        object-fit: cover;
        &[src=''] {
          display: none;
        }
      }
    }

    .controls {
      max-width: 54vh;
      margin-top: 24px;
      color: var(--color-text);

      .top-part {
        display: flex;
        justify-content: space-between;

        .track-info {
          .title {
            margin-top: 8px;
            font-size: 1.4rem;
            font-weight: 600;
            opacity: 0.88;
            display: -webkit-box;
            -webkit-box-orient: vertical;
            line-clamp: 1;
            -webkit-line-clamp: 1;
            overflow: hidden;
          }

          .subtitle {
            margin-top: 4px;
            font-size: 1rem;
            opacity: 0.58;
            display: -webkit-box;
            -webkit-box-orient: vertical;
            line-clamp: 1;
            -webkit-line-clamp: 1;
            overflow: hidden;
          }
        }
      }

      .top-right {
        display: flex;
        justify-content: space-between;

        .volume-control {
          display: flex;
          align-items: center;
        }

        .buttons {
          display: flex;
          align-items: center;

          button {
            margin: 0 0 0 4px;

            .svg-icon {
              width: 22px;
              height: 22px;
            }
          }
        }
      }

      .progress-bar {
        margin-top: 22px;
        display: flex;
        align-items: center;
        justify-content: space-between;

        span {
          font-size: 15px;
          opacity: 0.58;
        }

        .slider {
          width: 100%;
          flex-grow: grow;
          padding: 0 10px;
        }
      }

      .media-controls {
        display: flex;
        justify-content: center;
        margin-top: 18px;
        align-items: center;

        button {
          .svg-icon {
            width: 34px;
            height: 34px;

            &:deep(path) {
              stroke-width: 2.5;
            }

            &.play {
              width: 50px;
              height: 50px;
            }
          }
        }
      }
    }
  }

  .right-side {
    flex: 1;
    font-weight: 600;
    margin-right: 24px;
    z-index: 0;
  }

  .close-button {
    position: fixed;
    top: 24px;
    right: 24px;
    z-index: 300;
    border-radius: 0.75rem;
    display: flex;
    justify-content: center;
    align-items: center;
    opacity: 0.28;
    transition: 0.2s;

    &:hover {
      opacity: 0.88;
    }

    button {
      .svg-icon {
        width: 28px;
        height: 28px;

        &:deep(path) {
          stroke-width: 2.5;
        }
      }
    }
  }
}
</style>
